#include <Core/BoxApi/AsioBoxConnectionImpl.h>

namespace Core { namespace BoxApi {

namespace Aux {

static const int AsioIOServiceCon = 2;
/**
 *
 */
boost::shared_ptr<boost::asio::io_service> getSharedIOService() 
{
	static boost::shared_ptr<boost::asio::io_service> 
		sharedAsioIOService(new boost::asio::io_service(AsioIOServiceCon));
	return sharedAsioIOService;	
}

} // namespace Aux

/**
 * Public AsioBoxConnectionImpl's api
 */
AsioBoxConnectionImpl::AsioBoxConnectionImpl(BoxConnectionParams const & params) :
	IBoxConnection(params), 
	m_params(params), 
	m_commandStream()
{

}

AsioBoxConnectionImpl::~AsioBoxConnectionImpl() throw () 
{

}

void AsioBoxConnectionImpl::establishConnection() throw (std::exception) 
{
	m_commandStream.reset(new Aux::AsioSyncedCommandIOStream(*Aux::getSharedIOService()));
	boost::asio::ip::tcp::resolver resolver(*Aux::getSharedIOService());
	boost::asio::ip::tcp::resolver::query query(m_params.host, m_params.port);
	boost::asio::ip::tcp::resolver::iterator endPointIt = resolver.resolve(query);
	boost::asio::connect(m_commandStream->getSocket(), endPointIt);
}

void AsioBoxConnectionImpl::close() throw () 
{
	if (m_commandStream)	
		m_commandStream->close();
}
	
int AsioBoxConnectionImpl::getConnectionId() const throw (std::exception) 
{
	return m_params.id;
}

ICommandPtr AsioBoxConnectionImpl::sendMessageSync(ICommandPtr message) 
{	
	// TODO add errno set etc in fail cases
	ICommandPtr command;
	try 
	{
	if (!CommandCreateAdapters::pack<ProtobufCommandTranslator>(m_commandStream, message)) 
		return ErrorCommandPtr(
				new ErrorCommand("AsioBoxConnectionImpl::sendMessageSync failed to " 
							"pack or/and send message to the server", 
							ErrorCommand::INTERNAL_PROTOCOL_ERROR));
	command = CommandCreateAdapters::unPack<ProtobufCommandTranslator>(m_commandStream);		
	} 
	catch (std::exception const & expt /* in this scope could be throwed only via Aux::AsioSyncedCommandIOStream */) 
	{
		command.reset(new ErrorCommand(
			std::string("Unexpected error in AsioBoxConnectionImpl::sendMessageSync") +
				std::string(expt.what()), ErrorCommand::CONNECTION_BROKEN));
	}
	return command;
}

std::size_t AsioBoxConnectionImpl::writeRawData(std::vector<boost::uint8_t> const & data) throw()
{
	try
	{
		return m_commandStream->write(data);
		
	}
	catch(std::exception const & exc)
	{
		return 0;		
	}
	
}


/**
 * Private AsioBoxConnectionImpl's api
 */
	
} } // namespace Core, BoxApi

